package org.artifact.core.plugin.ioc;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import org.artifact.core.lang.AbstractPlugin;
import org.artifact.core.plugin.rpc.server.RpcService;
import org.artifact.core.server.ServerConfig;
import org.artifact.core.server.ServerContext;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class IocPlugin extends AbstractPlugin {
    private Map<String, Object> services = new HashMap<>();

    private String scanPackage;

    @Override
    public boolean start() {
        scanPackage = ServerConfig.me().deepGet("plugins.ioc.scanPackage");

        if (StrUtil.isEmpty(scanPackage)) {
            scanPackage = ServerContext.me().rootPackage();
        }
        scanPackage();
        // 开始注入
        for (Map.Entry entry : services.entrySet()) {
            inject(entry.getValue());
        }
        return true;
    }

    @Override
    public boolean stop() {
        return true;
    }

    /**
     * 扫描DAO
     */
    private void scanPackage() {
        Set<Class<?>> clazzs = ClassUtil.scanPackageByAnnotation(scanPackage, Service.class);
        for (Class<?> clazz : clazzs) {
            if (ClassUtil.isNormalClass(clazz)) {
                String name = AnnotationUtil.getAnnotationValue(clazz, Service.class);
                if (StrUtil.isBlank(name)) {
                    name = clazz.getName();
                }
                services.put(name, ReflectUtil.newInstance(clazz));
            }
        }


        clazzs = ClassUtil.scanPackageByAnnotation(scanPackage, RpcService.class);
        for (Class<?> clazz : clazzs) {
            if (ClassUtil.isNormalClass(clazz)) {
                RpcService rpcService = AnnotationUtil.getAnnotation(clazz, RpcService.class);
                String name = rpcService.value().getName();
                services.put(name, ReflectUtil.newInstance(clazz));
            }
        }
    }

    public <T> T inject(T t) {
        Field[] fields = ReflectUtil.getFields(t.getClass());
        for (Field field : fields) {
            Autowired autowired = field.getAnnotation(Autowired.class);
            if (autowired == null) {
                continue;
            }

            Class fieldClazz = field.getType();

            if (ClassUtil.isSimpleTypeOrArray(fieldClazz)) {
                throw new RuntimeException("注入错误");
            }

            // 明确指定
            String name = AnnotationUtil.getAnnotationValue(field, Autowired.class);
            if (StrUtil.isBlank(name)) {
                // 如果是接口或者抽象类
                if (fieldClazz.isInterface() || ClassUtil.isAbstract(fieldClazz)) {
//                    ReflectUtil.s
                    Set<Class<?>> subClass = ClassUtil.scanPackageBySuper(scanPackage, fieldClazz);
                    for (Class clazz : subClass) {
                        Service service = AnnotationUtil.getAnnotation(clazz, Service.class);
                        if (service == null) {
                            continue;
                        }
                        name = AnnotationUtil.getAnnotationValue(clazz, Service.class);

                        if (StrUtil.isBlank(name)) {
                            name = clazz.getName();
                        }
                        break;
                    }
                } else {
                    name = fieldClazz.getName();
                }
            }
            ReflectUtil.setFieldValue(t, field, services.get(name));
        }
        return t;
    }

    public <T> T getService(Class clazz) {
        String name = AnnotationUtil.getAnnotationValue(clazz, Service.class);
        if (StrUtil.isBlank(name)) {
            name = clazz.getName();
        }
        return getService(name);
    }

    public <T> T getService(String name) {
        return (T) services.get(name);
    }
}
